PART 09의 마무리는 라이브니스를 실제 출입 시스템에 결합하는 실습입니다. PART 05의 출석 체크, PART 07의 대규모 인식이 "누구인가"만 봤다면, 여기서는 그 앞에 "진짜 사람인가"라는 게이트를 세웁니다. 이 한 단계가 사진 한 장으로 뚫리던 시스템을 실제로 쓸 만하게 만듭니다.
게이트의 순서
핵심은 라이브니스를 인식보다 먼저 두는 것입니다. 가짜로 판정되면 인식까지 가지 않고 즉시 거부합니다.
진짜?} C -->|가짜| D[거부: 위조 의심] C -->|진짜| E[신원 인식] E --> F{등록자?} F -->|예| G[출입 허용] F -->|아니오| H[거부: 미등록]
라이브니스를 먼저 두면 두 가지 이득이 있습니다. 보안이 강해지고(가짜는 신원 비교 자체를 못 함), 자원도 아낍니다(가짜에 인식 연산을 낭비하지 않음).
라이브니스 + 인식 결합 코드
라이브니스는 DeepFace(2장), 인식은 InsightFace(PART 07)로 조합합니다. 단계별 최적 도구를 고르는 이 책의 방식입니다.
# 파일: access_gate.py"""라이브니스 게이트를 통과한 진짜 얼굴만 인식해 출입을 판정한다."""import pickleimport numpy as npimport cv2import faissfrom deepface import DeepFacefrom insightface.app import FaceAnalysis# 인식기(InsightFace)와 검색 인덱스(PART 07에서 구축)app = FaceAnalysis(name="buffalo_l", providers=["CPUExecutionProvider"])app.prepare(ctx_id=-1, det_size=(640, 640))index = faiss.read_index("faces.index")with open("names.pkl", "rb") as f: names = pickle.load(f)LIVENESS_MIN = 0.9 # 라이브니스 통과 기준RECOG_MIN = 0.4 # 인식 코사인 임계값def access_check(image_path): # 1단계: 라이브니스 게이트 try: faces = DeepFace.extract_faces(image_path, detector_backend="yunet", anti_spoofing=True) except ValueError: return "거부: 얼굴 없음" if not faces: return "거부: 얼굴 없음" f = faces[0] if not f["is_real"] or f["antispoof_score"] < LIVENESS_MIN: return f"거부: 위조 의심 (점수 {f['antispoof_score']:.2f})" # 2단계: 진짜 얼굴만 인식 img = cv2.imread(image_path) got = app.get(img) if not got: return "거부: 인식 실패" q = np.array([got[0].normed_embedding], dtype="float32") faiss.normalize_L2(q) D, I = index.search(q, k=1) if float(D[0][0]) < RECOG_MIN: return "거부: 미등록자" return f"출입 허용: {names[int(I[0][0])]} (유사도 {float(D[0][0]):.2f})"print(access_check("entry.jpg"))
흐름이 다이어그램 그대로입니다. 먼저 DeepFace로 라이브니스를 확인하고, is_real이 참이며 점수가 기준 이상일 때만 InsightFace 인식으로 넘어갑니다. 인식에서 등록자로 확인되면 출입을 허용합니다. 어느 단계에서든 막히면 그 이유와 함께 거부합니다.
다단계 방어로 강화하기
보안이 더 중요하면 패시브 라이브니스에 액티브를 더합니다. PART 03의 EAR(눈 깜빡임)을 챌린지로 쓰는 것입니다.
- 1차(패시브): DeepFace 라이브니스로 인쇄물·화면을 거른다.
- 2차(액티브): "눈을 깜빡이세요"를 요청하고, EAR 변화로 응답을 확인한다.
- 3차(인식): 두 관문을 통과한 진짜 얼굴만 신원 비교한다.
# 파일: active_challenge.py (개념 — PART 03 EAR 재사용)# 여러 프레임에서 EAR이 임계값 아래로 떨어졌다 돌아오면 깜빡임으로 인정if blink_detected_within(frames, timeout=3.0): print("액티브 라이브니스 통과")
정지 사진은 깜빡일 수 없으므로, 액티브 챌린지는 사진 공격을 거의 확실하게 막습니다. 다만 사용자에게 동작을 요구하므로, 보안 수준이 정말 높아야 할 때만 더하는 것이 좋습니다(1장).
운영을 위한 마무리 점검
- 순서 고정: 라이브니스 → 인식. 절대 인식부터 하지 않습니다.
- 연속 확인: 한 프레임이 아니라 여러 프레임 연속 통과를 요구해 순간 오판을 거릅니다.
- 로그와 알림: 위조 의심 거부는 기록하고, 반복되면 관리자에게 알립니다.
- 개인정보: 출입 기록·임베딩은 민감 정보입니다(PART 05·11).
실무 팁. 라이브니스를 도입하면 진짜 사용자가 가끔 거부되는 일(거짓 거부)이 생깁니다. 조명이 어둡거나 역광일 때 특히 그렇습니다. 그래서 거부됐을 때의 대안 경로(예: 사번·카드 인증으로 우회, 재시도 안내)를 반드시 함께 설계해야 합니다. 보안 게이트가 진짜 사용자를 가두는 일이 없도록, 막는 것과 동시에 "막혔을 때 어떻게 할지"를 준비하는 것이 완성된 시스템입니다.
이 장에서 기억할 것
출입 시스템은 라이브니스를 인식보다 먼저 두는 게이트 구조로 만듭니다. DeepFace 라이브니스로 진짜를 가린 뒤 InsightFace+faiss로 신원을 확인하면, 사진 공격을 막으면서 단계별 최적 도구를 씁니다. 보안이 더 높아야 하면 PART 03의 EAR을 액티브 챌린지로 더하고, 거짓 거부에 대비한 우회 경로를 반드시 설계합니다. 이로써 PART 09가 끝납니다. 다음 PART 10에서는 지금까지의 모든 조각을 모아 종합 실전 프로젝트를 만듭니다.